import React, {
  FC,
  forwardRef,
  useRef,
  useState,
  CanvasHTMLAttributes,
  useEffect,
  useImperativeHandle,
} from 'react';
import classNames from 'classnames';
import { isPc } from '../../utils/utils';

type platformProps = 'all' | 'phone' | 'pc';

interface BaseScratchCardProps {
  className?: string;
  platform?: platformProps;
  async?: boolean;
  width?: string | number;
  height?: string | number;
  hideImg?: string | JSX.Element;
  prizeImg?: string | JSX.Element;
  openingImg?: string | JSX.Element;
  style?: React.CSSProperties;
  loadRequest?: () => Promise<{ img: string | JSX.Element }>;
  successFun?: () => void;
  failedFun?: () => void;
  reset?: () => void;
  disabled?: boolean;
  drawRadius?: number;
  triggerPercent?: number;
}

type ScratchCardProps = BaseScratchCardProps &
  CanvasHTMLAttributes<HTMLCanvasElement>;

export const ScratchCard = forwardRef<any, ScratchCardProps>((props, ref) => {
  const prizeWrapperRef = useRef<HTMLDivElement>(null);
  const prizeHideRef = useRef<HTMLCanvasElement>(null);
  const prizeRef = useRef<HTMLCanvasElement>(null);

  const [canvasView, setCanvasView] = useState<{
    width: number;
    height: number;
  }>({ width: 0, height: 0 });
  const [asyncRequesting, setAsyncRequesting] = useState<boolean>(false);
  const [showPrize, setShowPrize] = useState<boolean>(false);

  // const [mouseDown, setMouseDown] = useState<boolean>(false)
  const mouseDownRef = useRef<boolean>(false);

  const {
    className,
    width,
    height,
    hideImg,
    prizeImg,
    openingImg,
    async,
    loadRequest,
    successFun,
    failedFun,
    style,
    disabled,
    platform,
    drawRadius,
  } = props;

  let { triggerPercent } = props;

  useImperativeHandle(ref, () => ({
    reset: () => {
      setShowPrize(() => false);
      setTimeout(() => {
        onLoad();
      }, 0);
    },
  }));

  useEffect(() => {
    onLoad();
  }, []);

  const onLoad = () => {
    const prizeWrapperEle = prizeWrapperRef.current;

    setCanvasView(() => ({
      width: prizeWrapperEle?.offsetWidth,
      height: prizeWrapperEle?.offsetHeight,
    }));

    if (prizeRef.current) {
      const prizeCanvas = prizeRef.current;
      prizeCanvas.style.width = `${prizeWrapperEle?.offsetWidth}px`;
      prizeCanvas.style.height = `${prizeWrapperEle?.offsetHeight}px`;
    }

    if (prizeHideRef.current) {
      const prizeHidecanvas = prizeHideRef.current;
      prizeHidecanvas.style.width = `${prizeWrapperEle?.offsetWidth}px`;
      prizeHidecanvas.style.height = `${prizeWrapperEle?.offsetHeight}px`;
    }

    loadPrizeImg(prizeWrapperEle?.offsetWidth, prizeWrapperEle?.offsetHeight);
  };

  const loadPrizeImg = (offsetWidth: number, offsetHeight: number) => {
    if (!prizeHideRef) return;

    let hideImgCtx = new Image();

    if (hideImg) {
      if (typeof hideImg === 'string') {
        hideImgCtx.src = hideImg + `?timeSign=${new Date().getTime()}`;
      } else {
        hideImgCtx.src = hideImg.props.src;
      }

      const hideCanvas = prizeHideRef.current?.getContext('2d');

      hideImgCtx.onload = () => {
        if (!hideCanvas) return;

        hideCanvas.beginPath();
        hideCanvas.clearRect(
          0,
          0,
          offsetWidth * devicePixelRatio,
          offsetHeight * devicePixelRatio,
        );

        if (!prizeHideRef.current) return;
        prizeHideRef.current.width = prizeHideRef.current.width;

        hideCanvas.drawImage(
          hideImgCtx,
          0,
          0,
          offsetWidth * devicePixelRatio,
          offsetHeight * devicePixelRatio,
        );
        hideCanvas.closePath();

        let prizeImgCtx = new Image();
        prizeImgCtx.crossOrigin = 'Anonymous';

        if (async) {
          if (typeof openingImg === 'string') {
            prizeImgCtx.src = openingImg;
          } else {
            prizeImgCtx.src = openingImg?.props.src;
          }
        } else {
          if (typeof prizeImg === 'string') {
            prizeImgCtx.src = prizeImg;
          } else {
            prizeImgCtx.src = prizeImg?.props.src;
          }
        }

        const prizeCanvas = prizeRef.current?.getContext('2d');

        prizeImgCtx.onload = () => {
          if (!prizeCanvas) return;

          prizeCanvas.beginPath();
          prizeCanvas.clearRect(
            0,
            0,
            offsetWidth * devicePixelRatio,
            offsetHeight * devicePixelRatio,
          );

          if (!prizeRef.current) return;

          prizeRef.current.width = prizeRef.current.width;

          prizeCanvas.drawImage(
            prizeImgCtx,
            0,
            0,
            offsetWidth * devicePixelRatio,
            offsetHeight * devicePixelRatio,
          );
          prizeCanvas.closePath();
          if (!disabled) {
            if (!prizeHideRef.current) return;

            if (platform != 'pc') {
              prizeHideRef.current.ontouchmove = e =>
                drawHandleTouchMove(e, 'phone');
              prizeHideRef.current.ontouchend = e =>
                drawMoveEnd(offsetWidth, offsetHeight);
            }
            if (platform != 'phone') {
              // prizeHideRef.current.
              prizeHideRef.current.onmousedown = () =>
                (mouseDownRef.current = true);

              prizeHideRef.current.onmousemove = e => {
                if (!mouseDownRef.current) return;
                drawHandleTouchMove(e, 'pc');
              };
              prizeHideRef.current.onmouseup = () => {
                mouseDownRef.current = false;
                drawMoveEnd(offsetWidth, offsetHeight);
              };
            }
          }
        };
      };
    }
  };

  const drawMoveEnd = (offsetWidth: number, offsetHeight: number) => {
    if (asyncRequesting) return;
    if (!prizeHideRef.current) return;
    const hideCanvas = prizeHideRef.current.getContext('2d');
    if (!hideCanvas) return;
    let imageData = hideCanvas.getImageData(
      0,
      0,
      offsetWidth * devicePixelRatio,
      offsetHeight * devicePixelRatio,
    );

    let allPX = imageData.width * imageData.height;

    let iNum = 0; //记录刮开的像素点个数

    for (let i = 0; i < allPX; i++) {
      if (imageData.data[i * 4 + 3] == 0) {
        iNum++;
      }
    }
    if (!triggerPercent || triggerPercent < 0 || triggerPercent > 1) {
      console.error('error param "triggerPercent"');
      triggerPercent = 0.333;
    }
    if (iNum >= allPX * triggerPercent) {
      setShowPrize(() => true);
      if (async) {
        loadRequest &&
          loadRequest()
            .then(data => {
              setShowPrize(() => true);
              asyncShowPrize(
                data,
                { offsetWidth, offsetHeight },
                successFun as () => {},
              );
            })
            .catch(data => {
              setShowPrize(() => true);
              asyncShowPrize(
                data,
                { offsetWidth, offsetHeight },
                failedFun as () => {},
              );
            });
      } else {
        //@ts-ignore
        asyncShowPrize(
          { img: prizeImg },
          { offsetWidth, offsetHeight },
          successFun,
        );
      }
    }
  };

  const asyncShowPrize = (
    data: { img: string | JSX.Element },
    view: { offsetWidth: number; offsetHeight: number },
    callBack?: () => {},
  ) => {
    let prizeImg = new Image();
    prizeImg.crossOrigin = 'Anonymous';

    if (typeof data.img == 'string') {
      prizeImg.src = data.img;
    } else {
      prizeImg.src = data.img.props.src;
    }
    const prizeCanvas = prizeRef.current?.getContext('2d');
    prizeImg.onload = () => {
      prizeCanvas?.beginPath();
      prizeCanvas?.drawImage(
        prizeImg,
        0,
        0,
        view.offsetWidth * devicePixelRatio,
        view.offsetHeight * devicePixelRatio,
      );
      prizeCanvas?.closePath();
      callBack && callBack();
    };
  };

  // 手指滑动开奖
  const drawHandleTouchMove = (
    e: TouchEvent | MouseEvent,
    type: platformProps,
  ) => {
    if (!prizeHideRef.current) return;
    e.preventDefault();

    const hideCanvas = prizeHideRef.current.getContext('2d');
    // console.log(prizeHideRef.current.getBoundingClientRect() )
    // console.log(e.touches[0].clientX, e.touches[0].clientY, document.body.offsetTop || document.documentElement.offsetTop)

    let x =
      (type == 'pc'
        ? (e as MouseEvent).clientX
        : (e as TouchEvent).touches[0].clientX) -
      prizeHideRef.current.getBoundingClientRect().x;
    let y =
      (type == 'pc'
        ? (e as MouseEvent).clientY
        : (e as TouchEvent).touches[0].clientY) -
      prizeHideRef.current.getBoundingClientRect().y;

    console.log(x, y);

    hideCanvas?.beginPath();
    //@ts-ignore
    hideCanvas.globalCompositeOperation = 'destination-out';
    hideCanvas?.arc(
      x * devicePixelRatio,
      y * devicePixelRatio,
      (drawRadius as number) * devicePixelRatio,
      0,
      Math.PI * 2,
      false,
    );
    hideCanvas?.fill();
    hideCanvas?.closePath();
  };

  return (
    <div
      ref={prizeWrapperRef}
      className={`ararin_sc_wrapper ${className || ''}`}
      style={{ ...style, width, height }}
    >
      <div className="ararin_sc_zone">
        {!showPrize && (
          <canvas
            ref={prizeHideRef}
            className="ararin_sc_prize_hide"
            width={canvasView.width * devicePixelRatio}
            height={canvasView.height * devicePixelRatio}
          />
        )}
        <canvas
          ref={prizeRef}
          className="ararin_sc_prize"
          width={canvasView.width * devicePixelRatio}
          height={canvasView.height * devicePixelRatio}
        />
      </div>
    </div>
  );
});

ScratchCard.defaultProps = {
  async: false,
  platform: 'all',
  drawRadius: 20,
  triggerPercent: 0.333,
};

export default ScratchCard;
